#include "stdafx.h"
#include "libraries.h"

#include "Application.h"
#include "Filesystem.h"
#include "VectorBatch.h"

using namespace Cvekas;

class VectorGraphics: public Application
{
public:
	VectorGraphics(HINSTANCE instance, const std::string& name, const std::string& log_filename)
		: Application(instance, name, log_filename)
	{
		Filesystem::init();
	}

	virtual ~VectorGraphics()
	{
	}

	virtual void initVideoDevice()
	{
		settings->insert("video", VideoSettings());

		(*settings)["video"]["ScreenWidth"] = 800;
		(*settings)["video"]["ScreenHeight"] = 600;
		(*settings)["video"]["VSync"] = false;
		(*settings)["video"]["Fullscreen"] = false;

		window = WindowPtr(new Window(instance, name));
		video_device->init(window);
	}

	void generate_blob(uint points, const Vector2& center, float radius, float delta_radius, float rotation, int mode)
	{
		Vector2 vec;
		polygon.assign(points, vec);

		for(uint i = 0; i < points; ++i)
		{
			float t = ((float)i / (float)points) * pi * 2.0f;
			float t2 = t * mode;
			vec.x = cos(t+rotation) * (radius + sin(t2) * delta_radius);
			vec.y = sin(t+rotation) * (radius + sin(t2) * delta_radius);
			polygon[i] = center + vec;
		}
	}

	void generate_strip(uint points, const Vector2& start, const Vector2& end, float delta_y, int mode)
	{
		Vector2 vec;
		line_strip.assign(points, vec);

		for(uint i = 0; i < points; ++i)
		{
			float t = ((float)i / (float)(points-1)) * pi * 2.0f;
			float t2 = t * mode;
			vec = lerp(start, end, (float)i / (float)(points-1));
			vec.y += sin(t2) * delta_y;
			line_strip[i] = vec;
		}
	}

	virtual void init()
	{
		vector_batch = VectorBatchPtr(new VectorBatch(main_renderer, 800, 600));
	}

	virtual bool update()
	{
		return true;
	}

	virtual bool render()
	{
		float t = Timer::getTimeMs() / 1000.0f;

		video_device->beginScene();

		vector_batch->drawLine(0, Vector2(40.0f + sin(t) * 30.0f, 40.0f + cos(t) * 30.0f), 
			Vector2(40.0f + sin(t + pi) * 30.0f, 40.0f + cos(t + pi) * 30.0f), 2.0f);
		vector_batch->drawLine(0, Vector2(40.0f + sin(t + 2.0f/3.0f*pi) * 30.0f, 40.0f + cos(t + 2.0f/3.0f*pi) * 30.0f), 
			Vector2(40.0f + sin(t + 2.0f/3.0f*pi + pi) * 30.0f, 40.0f + cos(t + 2.0f/3.0f*pi + pi) * 30.0f), 2.0f);
		vector_batch->drawLine(0, Vector2(40.0f + sin(t + 1.0f/3.0f*pi) * 30.0f, 40.0f + cos(t + 1.0f/3.0f*pi) * 30.0f), 
			Vector2(40.0f + sin(t + 1.0f/3.0f*pi + pi) * 30.0f, 40.0f + cos(t + 1.0f/3.0f*pi + pi) * 30.0f), 2.0f);

		generate_strip(32, Vector2(100.0f, 30.0f), Vector2(700.0f, 30.0f), sin(t) * 20.0f, 2);
		vector_batch->drawLineStrip(0, line_strip, 3.0f);

		vector_batch->drawTriangle(0, Vector2(70.0f + cos(t) * 20.0f, 150.0f + sin(t) * 20.0f), 
			Vector2(40.0f, 200.0f), Vector2(40.0f, 100.0f), Color(196, 255, 196, 196)); 
		vector_batch->drawTriangle(0, Vector2(70.0f + cos(t + pi) * 20.0f, 150.0f + sin(t + pi) * 20.0f), 
			Vector2(100.0f, 100.0f), Vector2(100.0f, 200.0f), Color(255, 196, 196, 196)); 
		
		generate_blob(64, Vector2(240.0f, 390.0f), 100.0f, sin(t) * 80.0f, t / 5.0f, 5);
		vector_batch->drawPolygon(0, polygon, Color(160, 196, 196, 128));

		generate_blob(64, Vector2(240.0f, 390.0f), 100.0f, sin(t + 0.4f) * 80.0f, 0.0f, 5);
		vector_batch->drawPolygon(0, polygon, Color(196, 160, 196, 128));

		generate_blob(64, Vector2(500.0f, 360.0f), 80.0f, 60.0f, -t, 2);
		vector_batch->drawPolygon(0, polygon, Color(160, 196, 160, 128));

		generate_blob(64, Vector2(550.0f, 200.0f), 60.0f, sin(t*3.0f) * 20.0f, t / 2.0f, 3);
		vector_batch->drawPolygon(0, polygon, Color(196, 196, 160, 128));

		vector_batch->present();
		main_renderer->render();
		video_device->endScene();

		main_renderer->endFrame();

		return true;
	}
private:
	VectorBatchPtr vector_batch;

	std::vector<Vector2> polygon;
	std::vector<Vector2> line_strip;
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
	try
	{
		VectorGraphics app(hInstance, "VectorGraphics", "VectorGraphics.log");
		app.run();
	}
	catch (std::exception& e)
	{
		MessageBox(NULL, e.what(), "Fatal error", NULL);
	}
	return 0;
}
